#region Using Statements
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
#endregion

namespace ContentBase.Sprites
{
    /// <summary>
    /// Provides a custom content processor that imports an array of individual sprite filenames from an XML file, loads them into memory, 
    /// <para>arranges them all onto a single larger texture, and returns the resulting sprite sheet.</para>
    /// </summary>
    [ContentProcessor(DisplayName = "Sprite Sheet - ContentBase")]
    public class SpriteSheetProcessor : ContentProcessor<string[], SpriteSheetContent>
    {        
        #region SpriteSheet Compression

        /// <summary>
        /// Possible compression formats.
        /// </summary>
        public enum CompressionFormat
        { 
            /// <summary>
            /// No compression applied.
            /// </summary>
            None,
            /// <summary>
            /// DXT compression applied.
            /// </summary>
            DxtCompressed
        };

        /// <summary>
        /// Specifies the compression format applied to the sprite sheet.
        /// </summary>
        [Description("Specifies the compression format applied to the sprite sheet.")]
        [DefaultValue(CompressionFormat.None)]
        [DisplayName("Texture Compression")]
        public CompressionFormat Compression
        {
            get;
            set;
        }

        #endregion

        /// <summary>
        /// Processes a collection of individual sprite images and packs them into a single larger texture.
        /// </summary>
        /// <param name="input">The input array of sprite filenames.</param>
        /// <param name="context">Context for the specified processor.</param>
        /// <returns>A sprite sheet containing all the individual sprite images.</returns>
        public override SpriteSheetContent Process(string[] input, ContentProcessorContext context)
        {
            SpriteSheetContent spriteSheet = new SpriteSheetContent();

            // list of source sprites contained in the sprite sheet
            List<BitmapContent> sourceSprites = new List<BitmapContent>();

            foreach (string fileName in input)
            {
                // store the name of each sprite
                string spriteName = Path.GetFileNameWithoutExtension(fileName);
                spriteSheet.SpriteNames.Add(spriteName, sourceSprites.Count);

                // load each sprite texture into memory and build it with its corresponding content processor
                ExternalReference<TextureContent> textureReference = new ExternalReference<TextureContent>(fileName);
                TextureContent texture = context.BuildAndLoadAsset<TextureContent, TextureContent>(textureReference, "TextureProcessor");

                // for the texture just built, get the largest element from its mipmap chain
                sourceSprites.Add(texture.Faces[0][0]);
            }

            // pack all the sprites into the sprite sheet
            BitmapContent packedSprites = SpriteSheetPacker.PackSprites(sourceSprites, spriteSheet.SpriteRectangles, context);

            // add the packed sprites as the only mipmap in the mipmap chain of the sprite sheet texture
            spriteSheet.Texture.Mipmaps.Add(packedSprites);

            // apply compression
            if (Compression == CompressionFormat.DxtCompressed)
            {
                spriteSheet.Texture.ConvertBitmapType(typeof(Dxt5BitmapContent));
            }

            return spriteSheet;
        }
    }
}